/**
 * 
 */

default_vertex = '\
	#ifdef GL_ES \n\
	precision highp float; \n\
	#endif \n\
	attribute vec3 position; \n\
	attribute vec3 normal; \n\
	attribute vec2 texCoord; \n\
	attribute vec2 lightCoord; \n\
	attribute vec4 color; \n\
	\n\
	varying vec2 vTexCoord; \n\
	varying vec2 vLightmapCoord; \n\
	varying vec4 vColor; \n\
	\n\
	uniform mat4 view; \n\
	uniform mat4 projection; \n\
	\n\
	void main(void) { \n\
		vec4 worldPosition = view * vec4(position, 1.0); \n\
		vTexCoord = texCoord; \n\
		vColor = color; \n\
		vLightmapCoord = lightCoord; \n\
		gl_Position = projection * worldPosition; \n\
	} \n\
';

default_fragment = '\
	#ifdef GL_ES \n\
	precision highp float; \n\
	#endif \n\
	varying vec2 vTexCoord; \n\
	varying vec2 vLightmapCoord; \n\
	uniform sampler2D texture; \n\
	uniform sampler2D lightmap; \n\
	\n\
	void main(void) { \n\
		vec4 diffuseColor = texture2D(texture, vTexCoord); \n\
		vec4 lightColor = texture2D(lightmap, vLightmapCoord); \n\
		gl_FragColor = vec4(diffuseColor.rgb * lightColor.rgb, diffuseColor.a); \n\
	} \n\
	';

model_fragment = '\
	#ifdef GL_ES \n\
	precision highp float; \n\
	#endif \n\
	varying vec2 vTexCoord; \n\
	varying vec4 vColor; \n\
	uniform sampler2D texture; \n\
	\n\
	void main(void) { \n\
		vec4 diffuseColor = texture2D(texture, vTexCoord); \n\
		gl_FragColor = vec4(diffuseColor.rgb * vColor.rgb, diffuseColor.a); \n\
	} \n\
	';

shader_attribs = ['position', 'normal', 'texCoord', 'lightCoord', 'color'];
shader_uniforms = ['view', 'projection', 'time', 'texture'];

var slShader = {};

slShader.defaultTexture	=	null;
slShader.defaultShader	=	null;
slShader.defaultProgram	= 	null;
slShader.white			= 	null;
slShader.lightmap		= 	null;

slShader.init = function( gl )
{
	slShader.defaultProgram = slShader.compileProgram( gl, default_vertex, default_fragment, shader_attribs, shader_uniforms );
	slShader.white = slShader.createSolidTexture( gl, [255,255,255,255] );
	
	slShader.defaultTexture = gl.createTexture();
	var image = new Image();
	image.onload = function()
	{
		gl.bindTexture( gl.TEXTURE_2D, slShader.defaultTexture );
		gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,image );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER,gl.LINEAR );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST );
		gl.generateMipmap( gl.TEXTURE_2D );
	};
	image.src = 'data/textures/wall.jpg';
	
	slShader.defaultShader = slShader.buildDefaultShader( gl );
};

slShader.buildDefaultShader = function( gl, surface )
{
	var diffuseStage = {
			map: ( surface ? surface.shaderName + '.tga' : null ),
			depthWrite : true,
			texture : null,
			program : null
	};
	
	if( surface )
	{
		slShader.loadTexture(gl, surface, diffuseStage );
	}
	else
	{
		diffuseStage.texture = slShader.defaultTexture;
	}
	
	var shader = {
			cull : gl.FONT,
			blend: false,
			sort: 0,
			stages:[ diffuseStage ]
	};
	return shader;
};

slShader.buildSourcShader = function( gl, surface, shader )
{
	for( var i = 0; i < shader.stages.length; ++i )
	{
		var stage = shader.stages[i];
		if( stage.map )
		{
			slShader.loadTexture(gl, surface, stage);
		}
		if( stage.shaderSrc && !stage.program )
		{
			stage.program = slShader.compileProgram(gl, stage.shaderSrc.vertex, stage.shaderSrc.fragment, shader_attribs, shader_uniforms);
		}
	}
};

slShader.LoadShader = function( gl, type, source )
{
	if( gl == null )
		return 0;
	// create shader
	var shader = gl.createShader( type );
	
	if ( shader == 0 )
		return 0;
	//load the source
	gl.shaderSource( shader, source );
	
	//compile source
	gl.compileShader( shader );
	
	var compiled = gl.getShaderParameter ( shader, gl.COMPILE_STATUS );
	
	if( !compiled )
	{
		alert(gl.getShaderInfoLog( shader ));
		gl.deleteShader( shader );
		return 0;
	}
	return shader;
	
};


slShader.compileProgram = function( gl, vertex, fragment, attribs, uniforms )
{
	if( gl == null )
		return 0;
	
	var vs = slShader.LoadShader( gl, gl.VERTEX_SHADER, vertex );
	var ps = slShader.LoadShader( gl, gl.FRAGMENT_SHADER, fragment );
	if( vs == 0 || ps == 0 )
		return 0;
	 
	var shaderProgram = gl.createProgram();
	
	gl.attachShader( shaderProgram, vs );
	gl.attachShader( shaderProgram, ps );
	gl.linkProgram( shaderProgram );
	
	if( !gl.getProgramParameter( shaderProgram, gl.LINK_STATUS ))
	{
		gl.deleteProgram(shaderProgram);
		gl.deleteShader(vs);
		gl.deleteShader(ps);
		return 0;
	}
	
	gl.useProgram(shaderProgram);
	
	shaderProgram.attrib = {};
	
	for( var i = 0; i < attribs.length; ++i )
	{
		shaderProgram.attrib[attribs[i]] = gl.getAttribLocation( shaderProgram, attribs[i]);
	}
	
	shaderProgram.uniform = {};
	for( var i = 0; i < uniforms.length; ++i )
	{
		shaderProgram.uniform[uniforms[i]] = gl.getUniformLocation( shaderProgram, uniforms[i]);
	}
	
	return shaderProgram;
};


slShader.loadTexture = function( gl, surface, stage )
{
	if( stage.map == null )
	{
		stage.texture = slShader.white;
		return;
	}
	
	stage.texture = slShader.defaultTexture;
	
	if( stage.map == 'anim')
	{
		stage.animTexture = [];
		for( var i = 0; i < stage.animMaps.length; ++i )
		{
			var animLoad = function( i ){
				stage.animTexture[i] = slShader.defaultTexture;
				slShader.loadTextureUrl(gl, stage, stage.animMaps[i], function(texture){
					stage.animTexture[i] = texture;
				});
			};
			
			animLoad(i);
		}
		stage.animFrame = 0;
	}
	else{
		slShader.loadTextureUrl(gl, stage, stage.map, function( texture ){
			stage.texture = texture;
		});
	}
	
};

slShader.loadTextureUrl = function( gl, stage, url, onload )
{
	var image = new Image();
	image.onload = function()
	{
		var texture = gl.createTexture();
		gl.bindTexture( gl.TEXTURE_2D, texture );
		gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST );
		
		if( stage.clamp )
		{
			gl.texParameterf( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
			gl.texParameterf( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
		}
		gl.generateMipmap( gl.TEXTURE_2D );
		onload( texture );
	};
	image.src = 'data/' + url;
};

slShader.createSolidTexture = function( gl, color )
{
	var data = new Uint8Array(color);
	var texture = gl.createTexture();
	gl.bindTexture(gl.TEXTURE_2D, texture);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, data);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
	return texture;
};

slShader.setShader = function( gl, shader )
{
	if( !shader )
	{
		gl.enable( gl.CULL_FACE );
		gl.cullFace( gl.BACK );
	}
	else if( shader.cull )
	{
		gl.enable( gl.CULL_FACE );
		gl.cullFace( shader.cull );
	}else
	{
		gl.disable( gl.CULL_FACE );
	}
	
	return true;
};

slShader.setShaderStage = function( gl, shader, shaderStage, time )
{
	var stage = shaderStage;
	if( !stage )
	{
		stage = slShader.defaultShader.stages[0];
	}
	
	if( stage.animFreq )
	{
		var animFrame = Math.floor(time*stage.animFreq) % stage.animTextrue.length;
		stage.texture = stage.animTexture[ animFrame ];
	}
	
	gl.blendFunc( stage.blendSrc, stage.blendDest );

	if( stage.depthWrite )
	{
		gl.depthMask( true );
	}
	else
	{
		gl.depthMask( false );
	}
	
	gl.depthFunc( stage.depthFunc );
	
	var program = stage.program;
	if( !program )
	{
		program = slShader.defaultProgram;
	}
	
	gl.useProgram( program );
	
	var texture = stage.texture;
	if( !texture )
	{
		texture = slShader.defaultTexture;
	}
	
	gl.activeTexture( gl.TEXTURE0 );
	gl.uniform1i( program.uniform.texture, 0 );
	gl.bindTexture( gl.TEXTURE_2D, texture );
	
	if( program.uniform.lightmap )
	{
		gl.activeTexture( gl.TEXTURE1 );
		gl.uniform1i( program.uniform.lightmap, 1 );
		gl.bindTexture( gl.TEXTURE_2D, slShader.lightmap );
	}
	
	if( program.uniform.time )
	{
		gl.uniform1f( program.uniform.time, time );
	}
	
	return program;
};

